package data_structures_and_algorithms.super_base;

import com.sun.xml.internal.fastinfoset.algorithm.BooleanEncodingAlgorithm;
import data_structures_and_algorithms.sort.learn.Code02_PartitionAndQuickSort;
import data_structures_and_algorithms.sort.learn.Example01;

import java.nio.file.FileStore;
import java.util.Arrays;

/**
 * @ClassName Random_Usage
 * @Description: TODO
 * @Author: yongliang.ma
 * @Create_time:2022/10/24 12:42
 */
public class Random_Usage {
    // Random函数基本知识
    public static void main(String[] args) {
        int count = 0;
        int times = 1000000;
        for (int i = 0; i < times; i++) {
            if (Math.random() <= 0.87)
                count++;
        }
        System.out.println((double)count/(double)times);
        count = 0;
        for (int i = 0; i < times; i++) {
            if (Math.random() * 8 <= 5)// 概率5/8约等于0.62
                count++;
        }
        System.out.println((double)count/(double)times);
    }

    // 扩展应用1：已知在[0, 1)区间中，获取的随机数小于x(0 <= x < k)的概率为x，那么我们如何设计一个函数是的获取一个数字落在[0,x]区间的概率为x^2
    public static class Random2{
        public double getRandomNum(){
            return Math.max(Math.random(), Math.random());// 两次申请随机数，然后取较大值作为结果
        }
    }

    // 扩展应用2：由获取1-5的随机数函数得到获取1-7的随机数
    public static class Random3{

        /**
         * 核心步骤复盘：
         * 1、搞出来获取0和1的随机函数
         * 2、用0、1这种二进制构建目标数字范围
         * 3、如果不是从0开始的可以考虑 + 1或者叫几之类的；当然也可以重开
         */
        // 题目给定义好的函数：可以等概率返回[1,5]中的整数
        public static int f1(){
            return (int)(Math.random() * 5) + 1;
        }

        // 我们自己构造的：等概率获取0，1两个数字（用这个表示后面的二进制数字上的位次）
        public static int f2(){
            int ans = 0;
            do {
                ans = f1();
            }while (ans == 3);
            return ans < 3? 0 : 1;
        }

        // 使用f2中获取0 和 1的随机数函数，我们构造二进制数字
        public static int f3(){
            // 因为题目要求1-7，所以我们这里构造3位即可
            return (f2() << 2) + (f2() << 1) + f2();
        }

        // 因为目标是获取1-7，所以我们需要舍弃f3中的0，老样子：如果是0重开
        public static int g(){
            int ans = 0;
            do{
                ans = f3();
            }while (ans == 0);
            return ans;
        }
        /**
         * 再来个题目巩固一下：
         * 给定3-19的随机数，获取20-56的随机数
         *
         * 思路：
         * 1、我们根据3-19获取随机数0和1
         * 2、题目要求获取20-56，那么我们获取到0-39即可，所以我们用6个二进制位就可以表示0-63范围内的数字，已经覆盖这个范围所以满足条件
         */
    }


    //  扩展应用3：有一个函数可以固定频率的返回1和0，比如返回0，概率是P，返回1的概率是1-P
    public static class Random4{
        // 某个函数以固定频率返回1和0
        public static int getFixNum(){
            return Math.random() > 0.97?1:0;
        }
        // 以50%的频率获取1和0
        public static int getNumWith50Percent(){
            int first = 0, second = 0;
            do{
                first = getFixNum();
                second = getFixNum();
            }while (first == second);
            // 构建二进制 1 0 类似这样，如果为01返回1，否则返回0
            return ((first << 1) + second) == 1 ? 1 :0;
        }
        // 改进1
        public static int getNumWith50Percent1(){
            int first = 0, second = 0;
            do{
                first = getFixNum();
                second = getFixNum();
            }while (first == second);
            // 构建二进制 1 0 类似这样，如果为01返回1，否则返回0（思路是这样保证概率一致但是不用真的计算）
            return first;// 随机返回一个即可，不必再做运算
        }
        // 改进2
        public static int getNumWith50Percent2(){
            int ans = 0;
            do{
                ans = getFixNum();
            }while (ans == getFixNum());
            // 构建二进制 1 0 类似这样，如果为01返回1，否则返回0（思路是这样保证概率一致但是不用真的计算）
            return ans;// 随机返回一个即可，不必再做运算
        }
    }


    // 对数器的应用
    public static class NumberChecker {
        public static int[] getRandomArray(int length, int maxValue){
            int[] nums = new int[length];
            for (int i = 0; i < length; i++) {
                nums[i] = (int)(Math.random() * maxValue);
            }
            return nums;
        }

        public static boolean isIncreasing(int[] nums){
            if (nums.length < 2)
                return true;
            for (int i = 1; i < nums.length; i++) {
                if (nums[i - 1] > nums[i])
                    return false;
            }
            return true;
        }

        public static int[] copyArray(int[] array){
            int[] nums = new int[array.length];
            for (int i = 0; i < array.length; i++) {
                nums[i] = array[i];
            }
            return nums;
        }

        public static boolean isEquals(int[] array1, int[] array2){
            if (array1.length != array2.length)
                return false;
            for (int i = 0; i < array1.length; i++) {
                if (array1[i] != array2[i])
                    return false;
            }
            return true;
        }


        // 依次检查实现的算法是否正确
        public static void main(String[] args) {
            int times = 1000000;
            for (int i = 0; i < times; i++) {
                int[] randomArray = getRandomArray(200, 100);
                int[] sourceArray = copyArray(randomArray);
//                Example01.selectSort(randomArray);
//                Example01.bubbleSort(randomArray);
//                Example01.insertSort(randomArray);

                Code02_PartitionAndQuickSort.quickSortLoop(randomArray);

                boolean increasing = isIncreasing(randomArray);
                if (!increasing){
                    System.out.println("数组排序出错" + Arrays.toString(sourceArray));
                    break;
                }
            }

            System.out.println("所有用例通过");
        }





    }








}
